import { latLng, LatLngLiteral, LeafletMouseEvent, Popup, PopupOptions } from 'leaflet';
import { FC, memo, ReactNode, useEffect, useRef } from 'react';
import { createPortal } from 'react-dom';
import { createRoot } from 'react-dom/client';
import { useMap } from 'react-leaflet';
import LeafletCanvasMarker from '../utils/LeafletCanvasMarker';
// @panzhiyue/leaflet-canvasmarker
export interface CanvasMarkerEventHandlerFnMap {
    click?(e: LeafletMouseEvent): void;
    dblclick?(e: LeafletMouseEvent): void;
    contextmenu?(e: LeafletMouseEvent): void;
    mousedown?(e: LeafletMouseEvent): void;
    mousemove?(e: LeafletMouseEvent): void;
    mouseup?(e: LeafletMouseEvent): void;
}

interface Props {
    position: LatLngLiteral | undefined;
    iconUrl?: string;
    iconSize?: [number, number]; // icon大小
    draggable?: boolean; // 是否允许拖动
    zIndexOffset?: number; // 层级偏移量
    eventHandlers?: CanvasMarkerEventHandlerFnMap; // 事件
    children?: ReactNode;
    popupOptions?: PopupOptions;
}

const CanvasMarker: FC<Props> = (props) => {
    const {
        position,
        iconUrl,
        iconSize,
        draggable,
        zIndexOffset,
        eventHandlers = {},
        children,
        popupOptions,
    } = props;

    const map = useMap();
    const isMove = useRef(false);
    const markerRef = useRef<LeafletCanvasMarker>();
    const popupRef = useRef<Popup>();

    useEffect(() => {
        if (!position) return;
        markerRef.current = new LeafletCanvasMarker(latLng(position.lat, position.lng), {
            img: {
                url: iconUrl || 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png',
                size: iconSize || [30, 40],
                rotate: 0,
                offset: { x: 0, y: 0 },
                zIndexOffset,
            },
        });

        if (children) {
            const dom = document.createElement('div');
            const root = createRoot(dom!);
            root.render(createPortal(children, dom));

            popupRef.current = new Popup({
                ...popupOptions,
            })
                .setLatLng(latLng(position.lat, position.lng))
                .setContent(() => {
                    return dom;
                });
            popupRef.current.options.offset;
            popupRef.current.close();
            markerRef.current.bindPopup(popupRef.current);
        }

        markerRef.current.addTo(map);

        markerRef.current.on('click', (e) => {
            eventHandlers.click && eventHandlers.click(e);
            if (popupRef.current) {
                popupRef.current.close();
            }
        });

        markerRef.current.on('mousemove', (e) => {
            if (popupRef.current) {
                popupRef.current.openOn(map);
            }
        });

        markerRef.current.on('dblclick', (e) => {
            eventHandlers.dblclick && eventHandlers.dblclick(e);
        });

        markerRef.current.on('contextmenu', (e) => {
            eventHandlers.contextmenu && eventHandlers.contextmenu(e);
        });

        markerRef.current.on('mousedown', (e) => {
            isMove.current = true;
            map.dragging.disable();
            eventHandlers.mousedown && eventHandlers.mousedown(e);
        });

        map.on('mousemove', (e) => {
            if (isMove.current && !draggable) {
                if (markerRef.current) {
                    markerRef.current.setLatLng(e.latlng);
                }
                eventHandlers.mousemove && eventHandlers.mousemove(e);
            }
        });

        map.on('mouseup', (e) => {
            if (isMove.current) {
                isMove.current = false;
                map.dragging.enable();
                eventHandlers.mouseup && eventHandlers.mouseup(e);
            }
        });

        return () => {
            if (!markerRef.current) return;
            markerRef.current.off('click');
            markerRef.current.off('dblclick');
            markerRef.current.off('contextmenu');
            markerRef.current.off('mousedown');
            markerRef.current.off('mousemove');
            map.off('mouseup');
            map.off('mousemove');
            markerRef.current.remove();
        };
    }, [
        children,
        draggable,
        eventHandlers,
        iconSize,
        iconUrl,
        map,
        popupOptions,
        position,
        zIndexOffset,
    ]);

    // useEffect(() => {
    //     if (!markerRef.current) return;
    //     markerRef.current.setLatLng(latAndLng);
    //     markerRef.current.redraw();
    // }, [latAndLng]);

    return null;
};

export default memo(CanvasMarker);
